<script lang="ts">
// 转达弹题答案格式
const transformAnswer = (arr) => {
  let res = [];
  for (let key in arr.options) {
    let obj = {
      value: arr.options[key],
      is_right: arr.answerIndex.includes(key) ? 1 : 0,
    };
    res.push(obj);
  }
  return res;
};

// 转化弹题数据格式
const transformQuestion = (arr: any) =>
  arr.map(({ question, time }) => ({
    exam_id: question.id,
    answer: "恭喜答对了！",
    illustration: "",
    option_list: transformAnswer(question),
    option_type: question.quType == 2 ? 2 : 1,
    show_analysis: "1",
    show_time: time,
    skip: "1",
    title: question.title,
    wrong_answer: "很遗憾，打错了~",
    wrong_time: "-1",
  }));
</script>

<script lang="ts" setup>
import * as courseApi from "@/api/train/course";
import * as courseMockApi from "@/mock/course";
import CourseItemItem from "./components/course-item-item.vue";
import BjyPlayer from "./components/bjy-player.vue";
import { useRouter, onBeforeRouteLeave } from "vue-router";
import { showNotify } from "@nutui/nutui";
import { useUserStore } from "@/store/modules/user";
import { useCourseStore } from "@/store/modules/course";
import "@nutui/nutui/dist/packages/dialog/style";
import useBjyPlayer from "./useBjyPlayer";
import { useIntersectionObserver } from "@vueuse/core";
import { getOSSURL } from "@/utils/utils";
import * as orderApi from "@/api/train/order";

const router = useRouter();
const userStore = useUserStore();
const courseStore = useCourseStore();

const props = defineProps({
  id: {
    type: String,
    required: true,
  },
});

/** 折叠栏目 */
const activeNames = ref<number | string>();
const hasUpdateItem = ref([]); // 记录已经更新的目录id
const collapseChange = (modeValue: string, currName: string, status: number) => {
  if (hasUpdateItem.value.includes(currName)) return;
  getCourseItemsDetail(currName);
  hasUpdateItem.value.push(currName);
};

// 课程详情
const course = ref<Course | null>(null);
async function loadCourse() {
  const res = await courseApi.getCourseById(props.id);
  console.log("课程", res);
  course.value = res.data;
}

// 课程目录
const courseCatalogList = ref<CourseCatalog[] | null>(null);
const rootCatalogList = computed(() => courseCatalogList.value?.filter((item) => item.parentId === 0));
async function loadCourseCatalogList() {
  const res = await courseApi.getCourseCatalogListByCourseId(props.id);
  console.log("目录", res);
  courseCatalogList.value = res.data;
}

// 课程条目
const courseItemList = ref<CourseItem[] | null>(null);
async function loadCourseItemList() {
  const res = await courseApi.getCourseItemListByCourseId(props.id);
  console.log("条目", res);
  courseItemList.value = res.data;
}

// 课程条目的详情
const courseItemDetailsMap = reactive<{
  [key in CourseItem["courseType"]]?: { string: CourseVideo | CourseArticle };
}>({});
/**
 * 获取对应目录下的条目详细信息
 * @param id 目录id
 */
const getCourseItemsDetail = async (catalogId: string) => {
  const items = courseItemList.value.filter((item) => item.catalogId == catalogId);

  // 构造请求参数
  const itemIds: Parameters<typeof courseApi.getItemsDetail>[0] = {};
  items.forEach((item) => (itemIds[item.courseType] || (itemIds[item.courseType] = [])).push(item.courseTypeId));
  if (!Object.keys(itemIds).length) return;

  // 将请求结果应用到记录中
  const res = await courseApi.getItemsDetail(itemIds);
  Object.entries(res.data).forEach(([itemType, detailList]) => {
    detailList.forEach((detail) => {
      (courseItemDetailsMap[itemType] || (courseItemDetailsMap[itemType] = {}))[detail.id] = detail;
    });
  });
};

// 是否免费
const isFree = computed(() => !course.value?.price);

/** 前往购买 */
async function gotoBuy() {
  if (!isFree.value) {
    router.push({
      path: `/buy/${course.value?.skuId}`,
    });
  } else {
    if (!course.value) return;
    const res = await orderApi.createOrder({
      skuId: course.value.skuId,
      amount: 1,
      orderPrice: 0,
      remark: "",
    });
    const orderId = res.data;
    const orderRes = await orderApi.getOrderById(orderId);
    if (orderRes.data) {
      showNotify.primary("报名成功");
      await init();
      course.value.purchased = true;
    }
  }
}

// 处理学习进度更新逻辑
const currVideoCourseItem = ref(null); // 当前播放的视频条目id
const oldVideoCourseItem = ref(null); // 上一个播放的视频条目id
/** 百家云视频切换，触发回调，更新视频学习进度 */
const replaceVideo = async (time: number, duration: number) => {
  await courseMockApi.updateStudyRecord({
    courseId: props.id,
    courseItemId: oldVideoCourseItem.value.id,
    perentage: parseFloat((time / duration).toFixed(2)) * 100,
  });
};

/** 路由导航守卫 */
// onBeforeRouteLeave(async () => {
// 离开页面时，如果当前播放着视频，提交播放进度
// if (focusCourseItem.value?.courseType == 1) {
//   oldVideoCourseItem.value = currVideoCourseItem.value;
//   replaceVideo(bjyPlayer.value.currentTime, bjyPlayer.value.duration);
// }
// return true;
// });

// 重播
const resetSeek = () => {
  bjyPlayer.value.seek(0);
  bjyPlayer.value.play();
  bjyPlayer.value.visibleEndMask(false);
};
// 播放下一个
const playNext = () => {
  bjyPlayer.value.visibleEndMask(false);
  // 获取当前播放条目的索引
  let videoCourseItem = courseItemList.value.filter((item) => item.courseType == 1);
  let index = videoCourseItem.findIndex((item) => item.id == currVideoCourseItem.value.id);
  // 获取下一个条目
  let nextItem = videoCourseItem[index + 1];
  if (nextItem) {
    focusCourseItem.value.id = nextItem.id;
    activeNames.value = nextItem.catalogId;
    if (nextItem && nextItem.courseType == 1) {
      handleCourseItemClick(nextItem);
    }
  }
};

const bjyPlayer = ref(null);
const focusCourseItem = ref<CourseItem | null>(null); // 点击的视频条目, 用于高亮显示
const playingVideoSource = ref<Record<string, any> | null>(null);
const playerOptions = ref<Record<string, any>>({});

// 处理条目点击事件
const buyDialogVisible = ref(false);
async function handleCourseItemClick(courseItem: CourseItem) {
  const { courseType, courseTypeId } = courseItem;
  // 没有购买该课程，通过点击的条目是非视频类型的，return
  // 条目是视频类型,没有购买该课程，且不是免费试看，return
  if (!course.value?.purchased && !courseItem.isFree) {
    buyDialogVisible.value = true;
    return;
  }

  focusCourseItem.value = courseItem; // 展示条目高亮
  ({
    // 视频
    1: async () => {
      const video: CourseVideo | undefined = courseItemDetailsMap[courseType][courseTypeId];

      // 题目
      const videoQuestionRes = await courseMockApi.getCourseVideoQuestion(courseTypeId);
      const videoQuestion = transformQuestion(videoQuestionRes.data);

      // 获取百家云播放token并播放
      const { data: token } = await courseApi.getPlayerTokenByBjyVideoId(video.bjyVideoId);
      playingVideoSource.value = {
        vid: video.bjyVideoId,
        token,
      };

      // 记录播放的视频条目id
      oldVideoCourseItem.value = currVideoCourseItem.value;
      currVideoCourseItem.value = courseItem;

      const tenantLogoUrl = getOSSURL(userStore.tenantInfo?.logoOssUrl);

      // 处理视频播放器的配置数据
      playerOptions.value = useBjyPlayer({
        sendQuestion: videoQuestion, // 弹题数据
        poster: video.videoCoverUrl,
        bulletText: userStore.userInfo.nickname,
        // TODO: 这里换成租户的logo
        waterMarkUrl: tenantLogoUrl,
        seek: courseItem.studyProgress ? Math.ceil(courseItem.videoDuration * parseFloat((courseItem.studyProgress / 100).toFixed(2))) : 0,
      }).playerOptions;

      window.scrollTo({
        top: 0,
        left: 0,
        behavior: "smooth",
      });
    },
    // 图文
    2: async () => {
      router.push({
        path: `/course/article/${courseItem.courseTypeId}`,
      });
    },
    // 题目集合
    3: async () => {
      // 跳转到题目页面
      router.push(`/practice/set?id=${courseItem.courseTypeId}`);
    },
    // 直播
    4: async () => {
      const live: CourseLive | undefined = courseItemDetailsMap[courseType][courseTypeId];

      // 获取之别见状态
      const liveStatusRes = await courseApi.getCourseLive(live.id);
      const { liveStatus, liveUrl } = liveStatusRes.data;

      if (liveStatus === 0) {
        showNotify.primary("当前直播间未开播");
      } else {
        // 跨页面传参
        courseStore.setLiveUrl(liveUrl);
        router.push({ path: "/course/live" });
      }
    },
  })[courseType]();
}

// 进入页面时，初始化历史展开折叠栏目以及最后播放的视频
const initHistoryData = async () => {
  const { courseItemId, catalogId } = courseStore.history;

  if (catalogId) {
    activeNames.value = catalogId;
    await getCourseItemsDetail(catalogId);
    hasUpdateItem.value.push(catalogId);
  }
  if (courseItemId) {
    let item = courseItemList.value.find((item) => item.id == courseItemId);
    if (item.courseType == 1) await handleCourseItemClick(item);
  }
};

const init = async () => {
  await loadCourse();
  await Promise.all([loadCourseCatalogList(), loadCourseItemList()]);
  await initHistoryData();
};

/** 初始化数据 */
onMounted(init);

onActivated(init);

// 退出页面时，销毁播放器
onUnmounted(() => {
  // 存储当前打开的章节
  courseStore.updateHistory({
    courseItemId: focusCourseItem.value?.id,
    catalogId: focusCourseItem.value?.catalogId,
  });

  playingVideoSource.value = null; // 销毁播放器
  activeNames.value = null; // 重置折叠栏目
  hasUpdateItem.value = []; // 重置已更新的目录id
});

// 顶部导航栏
const detailEle = ref<HTMLDivElement>();
const detailIsVisible = ref(false);

useIntersectionObserver(detailEle, ([{ isIntersecting }]) => (detailIsVisible.value = isIntersecting));

const tabValue = computed<"home" | "detail">({
  get() {
    return detailIsVisible.value ? "detail" : "home";
  },
  set(val) {
    if (val === "detail") {
      detailEle.value?.scrollIntoView({
        behavior: "smooth",
      });
    } else {
      window.scrollTo({
        top: 0,
        left: 0,
        behavior: "smooth",
      });
    }
  },
});
</script>

<template>
  <div class="bg-gray-1">
    <nut-navbar class="sticky top-0 z-10" style="--nut-navbar-margin-bottom: 0" @click-back="router.back()">
      <template #left>
        <div>返回</div>
      </template>

      <template #content>
        <nut-tabs v-model="tabValue">
          <nut-tab-pane title="首页" pane-key="home" />
          <nut-tab-pane title="详情" pane-key="detail" />
        </nut-tabs>
      </template>
    </nut-navbar>

    <!-- 百家云 -->
    <BjyPlayer
      ref="bjyPlayer"
      v-if="playingVideoSource"
      :vid="playingVideoSource.vid"
      :token="playingVideoSource.token"
      :marquee="playerOptions.bullet"
      :seek="playerOptions.seek"
      :menory="false"
      @replaceVideo="replaceVideo"
      @resetSeek="resetSeek"
      @playNext="playNext"
      :waterMark="playerOptions.waterMark"
      :sendQuestion="playerOptions.sendQuestion"
    />
    <!-- 百家云 -->

    <!-- 默认封面 -->
    <nut-image v-else class="min-h-[200px] w-full" :src="getOSSURL(course?.courseCoverUrl)" fit="cover" show-loading />
    <!-- 默认封面 -->

    <!-- 标题 -->
    <div class="px-4 py-3 bg-white">
      <h1 class="text-xl">{{ course?.courseName }}</h1>
    </div>
    <!-- 标题 -->

    <!-- 课程目录 -->
    <div class="my-3 py-3 bg-white">
      <h2 class="px-4 text-lg">课程目录</h2>
      <p class="px-4 text-gray-5 text-sm">共{{ courseCatalogList?.length }}个课程</p>

      <div class="mt-2">
        <nut-collapse v-model="activeNames" :accordion="true" @change="collapseChange">
          <template v-for="(rootCatalog, rootIndex) in rootCatalogList" :key="rootCatalog.id">
            <!-- 多级 -->
            <template v-if="courseCatalogList?.filter((item) => item.parentId === rootCatalog.id).length">
              <div class="px-4 py-3">{{ rootIndex + 1 }}. {{ rootCatalog.catalogName }}</div>
              <nut-collapse-item
                v-for="(courseCatalog, subIndex) in courseCatalogList?.filter((item) => item.parentId === rootCatalog.id)"
                :key="courseCatalog.id"
                :name="courseCatalog.id"
                :title="rootIndex + 1 + '.' + (subIndex + 1) + ' ' + courseCatalog.catalogName"
                :value="'小节共' + courseItemList?.filter((i) => i.catalogId === courseCatalog.id).length || 0 + '个'"
              >
                <course-item-item
                  v-for="courseItem in courseItemList?.filter((i) => i.catalogId === courseCatalog.id)"
                  :key="courseItem.id"
                  :purchased="course?.purchased || false"
                  :course-item="courseItem"
                  :course-item-detail="courseItemDetailsMap[courseItem.courseType]?.[courseItem.courseTypeId]"
                  @click="handleCourseItemClick(courseItem)"
                  :currCourseItemId="focusCourseItem?.id"
                />
              </nut-collapse-item>
            </template>

            <!-- 单级 -->
            <template v-else>
              <nut-collapse-item :name="rootCatalog.id" :title="rootIndex + 1 + '. ' + rootCatalog.catalogName">
                <course-item-item
                  v-for="courseItem in courseItemList?.filter((i) => i.catalogId === rootCatalog.id)"
                  :key="courseItem.id"
                  :purchased="course?.purchased || false"
                  :course-item="courseItem"
                  :course-item-detail="courseItemDetailsMap[courseItem.courseType]?.[courseItem.courseTypeId]"
                  @click="handleCourseItemClick(courseItem)"
                  :currCourseItemId="focusCourseItem?.id"
                />
              </nut-collapse-item>
            </template>
          </template>
        </nut-collapse>
      </div>
    </div>

    <!-- 课程介绍 -->
    <div ref="detailEle" class="my-3 bg-white">
      <div class="detail-content" v-html="course?.courseDetail"></div>
    </div>

    <!-- 购买弹窗 -->
    <nut-dialog
      teleport="#app"
      title="提示"
      content="购买后即可解锁完整课程"
      ok-text="立即购买"
      cancel-text="我再想想"
      @ok="gotoBuy"
      @cancel="buyDialogVisible = false"
      v-model:visible="buyDialogVisible"
    >
    </nut-dialog>

    <!-- 底部栏 -->
    <div class="h-18"></div>
    <div v-if="!course?.purchased" class="fixed bottom-0 left-0 right-0 px-3 pb-3 pt-2 bg-white b-t b-t-gray-2">
      <nut-button type="primary" block @click="gotoBuy">立即{{ isFree ? "报名" : "购买" }}</nut-button>
    </div>
  </div>
</template>

<style>
.detail-content img {
  display: inline-block;
  width: 100%;
}
</style>
